import datetime, time
from   google.appengine.ext import db

#=========================================================================
# ironcap.serialization.dictserializer.entity_to_dict
#=========================================================================

DATASTORE_TYPES = (int, long, float, bool, dict, basestring, list)

def entity_to_dict(obj, classKey=None):
	""" converts an entity (excluding references as convention) into a dict """
	ret = {}
	for key, prop in obj.properties().iteritems():
		value = getattr(obj, key)
		if value is None or isinstance(value, DATASTORE_TYPES):
			ret[key] = value
			
		elif isinstance(value, datetime.date):
			ms  = time.mktime(value.utctimetuple()) * 1000
			ms += getattr(value, 'microseconds', 0) / 1000
			ret[key] = int(ms)
			
		elif isinstance(value, db.GeoPt):
			ret[key] = {'lat' : value.lat, 'lon' : value.lon}
			
		elif isinstance(value, db.Model):
			# prevent these from appearing in the serializied result.
			# reference is a special property in use to back reference 
			# entities.
			if not key == 'reference':
				if not key == 'parent_node':
					ret[key] = entity_to_dict(value)
		else:
			raise ValueError('cannot encode ' + repr(prop))
	return ret
	
#=========================================================================
# ironcap.serialization.dictserializer.object_to_dict
#=========================================================================

def object_to_dict(obj, classkey=None):
    if isinstance(obj, dict):
        for k in obj.keys():
            obj[k] = object_to_dict(obj[k], classkey)
        return obj
		
    elif hasattr(obj, "__iter__"):
        return [object_to_dict(v, classkey) for v in obj]
		
    elif hasattr(obj, "__dict__"):
        data = dict([(key, object_to_dict(value, classkey)) 
            for key, value in obj.__dict__.iteritems() 
            if not callable(value) and not key.startswith('_')])
        if classkey is not None and hasattr(obj, "__class__"):
            data[classkey] = obj.__class__.__name__
        return data
		
    else:
        return obj

#=========================================================================
# ironcap.serialization.dictserializer.serialize
#=========================================================================
		
def serialize(obj, classKey=None):
	""" serializes both python objects and datastore entities """
	
	# dictionary
	if isinstance(obj, dict):
		ret = {}
		for k, v in obj.iteritems():
			if isinstance(v, db.Model):
				ret[k] = entity_to_dict(v)
			else:
				ret[k] = object_to_dict(v)
		return ret
	
	# array
	elif hasattr(obj, "__iter__"):
		ret = []
		for n in obj:
			if isinstance(n, db.Model):
				ret.append( entity_to_dict(n) )
			else:
				ret.append( object_to_dict(n) )
		return ret
	# object
	else:
		if isinstance(obj, db.Model):
			return entity_to_dict(obj)
		else:
			return object_to_dict(obj)
		